﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.Linq;
using System.Linq;
using System.Text;

namespace BusinessLayer
{
    public sealed class MultipleResultsBag : IMultipleResults
    {
        private IList<object> list;

        public MultipleResultsBag()
        {
            list = new List<object>();
        }

        public MultipleResultsBag(IList<object> list)
        {
            this.list = list;
        }

        public object ReturnValue { get { return null; } }

        private void AddRangeInternal(IEnumerable<object> collection)
        {
            if (collection == null) return;
            foreach (var value in collection)
            {
                list.Add(value);
            }
        }

        public void Add(DataTable value)
        {
            list.Add(value);
        }

        public void AddRange(DataTable[] values)
        {
            if (values.IsNullOrEmpty()) return;
            AddRangeInternal(values.ToList());
        }

        public void Add(DataSet dataSet)
        {
            if (dataSet == null || dataSet.Tables.Count == 0) return;
            AddRange(dataSet.Tables.OfType<DataTable>().ToArray());
        }

        public void Insert<TElement>(int index, TElement item)
        {
            var elementCollection = GetCollection<TElement>();
            if (elementCollection == null) throw new ArgumentException();
            elementCollection.Insert(index, item);
        }

        public void Add<TElement>(TElement item)
        {
            AddRange(new TElement[] { item });
        }

        public void AddRange<TElement>(ICollection<TElement> collection)
        {
            var elementCollection = GetCollection<TElement>();
            if (elementCollection == null)
            {
                list.Add(new Collection<TElement>(new List<TElement>(collection)));
            }
            else
            {
                foreach (var item in collection)
                {
                    elementCollection.Add(item);
                }
            }
        }

        private Collection<TElement> GetCollection<TElement>()
        {
            return list.FirstOrDefault(i => i is Collection<TElement>) as Collection<TElement>;
        }

        public IEnumerable<TElement> GetResult<TElement>()
        {
            var result = list.FirstOrDefault(i => i is IEnumerable<TElement>);
            return result == null ? new TElement[] { } : result as IEnumerable<TElement>;
        }

        public ReadOnlyCollection<TElement> GetReadOnlyCollection<TElement>()
        {
            Collection<TElement> collection = GetCollection<TElement>();
            if (collection == null)
            {
                collection = new Collection<TElement>() { };
            }
            return new ReadOnlyCollection<TElement>(collection);
        }

        public DataTable this[string tableName]
        {
            get
            {
                if (string.IsNullOrWhiteSpace(tableName)) return null;
                var result = list.OfType<DataTable>().FirstOrDefault(i => i.TableName.Equals(tableName, StringComparison.OrdinalIgnoreCase));
                return result == null ? null : result;
            }
        }

        public static MultipleResultsBag Combine(params IMultipleResults[] values)
        {
            if (values == null) throw new ArgumentNullException("values");
            return Combine(null, values.Cast<MultipleResultsBag>().ToArray());
        }

        public static MultipleResultsBag Combine(params MultipleResultsBag[] values)
        {
            return Combine(null, values);
        }

        private static MultipleResultsBag Combine(MultipleResultsBag bag, params MultipleResultsBag[] values)
        {
            if (bag == null)
            {
                bag = new MultipleResultsBag();
            }
            if (!values.IsNullOrEmpty())
            {
                int capacity = bag.list.Count;
                for (int i = 0; i < values.Length; i++)
                {
                    if (values[i] == null) continue;
                    capacity += values[i].list.Count;
                }

                var list = new List<object>(capacity);
                for (int i = 0; i < values.Length; i++)
                {
                    if (values[i] == null) continue;
                    list.AddRange(values[i].list);
                }
                bag.list = new Collection<object>(list);
            }
            return bag;
        }

        public void Dispose() { }
    }
}
